#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QEventLoop>
#include <QSslConfiguration>
#include <QSsl>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QXmlStreamReader>
#include <QDir>
#include <QAbstractSocket>

#include <QDebug>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>

#if 0 //for linux
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#else //for windows
#pragma comment( lib, "ws2_32.lib" )
#endif

#include "main.h"
#include "otahelperclient.h"


#define ENV_ESYNC_DATA_DIR	"ESYNC_DATA_DIR"
#define _stats_on(fmt, ...) emit errStatusChanged(0, fmt, ##__VA_ARGS__)

static int getKeyValue(const char *str, const char *key, char *const value, unsigned int len);

OtaHelperCli::OtaHelperCli(QObject * parent)
    : QThread(parent)
	, _campaignId (0)
    , _addr (QByteArray())
    , _port (0)
{
    _opCmd = new CommandSock();
    connect(_opCmd, SIGNAL(error(QString)), this, SLOT(onCommandError(QString)));
}

OtaHelperCli::~OtaHelperCli()
{
    if (_opCmd->isConnAlive())
        _opCmd->slotDisconnectOperateServer();
}

void OtaHelperCli::onCommandError(QString err)
{
	qDebug() << "command err:" << err;
	emit errStatusChanged(1, err);
}

bool OtaHelperCli::_initConnection()
{
	_isRunning = false;

	_opCmd->slotConnectOperateServer(this->_addr.data(), this->_port);
	if (!_opCmd->isConnAlive())
		return false;

	_isRunning = true;
	return true;
}

int OtaHelperCli::_getRequest(const char * request)
{
	static struct evt_requsts {
		int id; char words[32];
	} hmi_popup_wins[] = {
		//BOOK_INSTALL, "UPDATE_PROMPT",
		INSTALL_NOW, "UPDATE_PROMPT",
		UPDATE_SUCCESS, "UPDATE_SUCCESS",
		UPDATE_FAIL, "UPDATE_FAIL",
		INSTALL_NOW, "START_UPDATE",
		POLICY_FAIL, "POLICY_FAIL",
		PROGRESS_CHG, "PROGRESS_CHG",
	};

	char win[32] = {0};
	char cnt[20] = {0};
	if (!getKeyValue(request, "type=", win, 32 - 1)) {
		qDebug ("Get type is failed!");
		return -1;
	}

	if (getKeyValue(request, "campaign_id=", cnt, 19)) {
		unsigned int tt;
		if (sscanf(cnt, "%u", &tt) <= 0) {
			qDebug ("Convert %s to campaign id is failed!", cnt);
			return -1;
		} else
			this->_campaignId = tt;
	} else {
		qDebug ("Get campaign id is failed!");
		return -1;
	}

	int i = 0;
    for (i=0; i < sizeof(hmi_popup_wins)/sizeof(hmi_popup_wins[0]); i ++) {
		if (0 == strcmp(win, hmi_popup_wins[i].words)) {
			qDebug() << "Get request" << win;
			switch (i) {
				case PROGRESS_CHG:
				{
					if (getKeyValue(request, "total_percent=", cnt, 19)) {
						unsigned int tt;
						if (sscanf(cnt, "%u", &tt) <= 0) {
							qDebug ("Convert %s to total_percent is failed!", cnt);
							return -1;
						} else
							this->total_percent = tt;
					}
					if (getKeyValue(request, "current_percent=", cnt, 19)) {
						unsigned int tt;
						if (sscanf(cnt, "%u", &tt) <= 0) {
							qDebug ("Convert %s to current_percent is failed!", cnt);
							return -1;
						} else
							this->current_percent = tt;
					}
				}
				break;
			}
			emit popupWindow (hmi_popup_wins[i].id);
			return 0;
		}
	}
	return -1;
}

void OtaHelperCli::run()
{
	int stachking = 0;
	while (1) {
		if (! _initConnection()) {
			qDebug() << "Waiting ota on () ...";
			stachking++; stachking = (stachking % 4);
			_stats_on ("Waiting ota on(" + this->_addr + ":" + QString("%1").arg(this->_port) + ")," + "not connected ...");
		} else {
			_stats_on ("Ota on(" + this->_addr + ":" + QString("%1").arg(this->_port) + ")," + "connected ...");
		}
		while (_isRunning) {
			QByteArray data;
			_opCmd->slotReceiveData(&data, 300);
			if (!data.isEmpty()) {
				_stats_on (QByteArray("Re:") + data);
				QList<QByteArray> lines = data.split('\n');
				for (int i = 0; i < lines.length(); i ++) {
					QByteArray line = lines.at(i);
					if (!line.isEmpty()) {
						qDebug("### [%s] ###\n", line.data());
						if (_getRequest(line) < 0) {
							qDebug() << "...get Request failed";
						}
					}
				}
			}
		}
		usleep(500000);
	}
}

void OtaHelperCli::userClicked(int id)
{
	static struct {
		unsigned int id;
		char words[20];
	} hmi_evt_items[] = {
		INSTALL_NOW, "install_now", //OTA_HMI_EVENT_INSTALL_NOW
		BOOK_INSTALL, "book_install", //OTA_HMI_EVENT_BOOK_INSTALL
		CHK_POL, "check_policy", //OTA_HMI_EVENT_CHECK_POLICY
		DBG_RESET, "dbg_reset", //OTA_HMI_EVENT_DBG_RESET
		DEBUG_EXPORT_LOG, "dbg_export_log", //OTA_HMI_EVENT_DBG_EXPORT_LOG
	};
	qDebug() << "Err! pipe not exist!";
	if (! this->_isRunning) {
		qDebug() << "Err! pipe not exist!";
		return;
	}

	char CmdLineBuf[512] = {0};
	switch (id) {
		case INSTALL_NOW:
			sprintf(CmdLineBuf, "type=\"%s\", campaign_id=\"%d\", install_now=\"%d\", \n",hmi_evt_items[id - 1].words, this->_campaignId, this->isClickOK);
		break;
		case BOOK_INSTALL:
			sprintf(CmdLineBuf, "type=\"%s\", campaign_id=\"%d\", book_install=\"%d\", \n",hmi_evt_items[id - 1].words, this->_campaignId, this->booktime);
		break;
		case CHK_POL:
			sprintf(CmdLineBuf, "type=\"%s\", campaign_id=\"%d\", check_policy=\"%d\", \n",hmi_evt_items[id - 1].words, this->_campaignId, this->polcmd);
		break;
		case DBG_RESET:
			sprintf(CmdLineBuf, "type=\"%s\", campaign_id=\"%d\",\n",hmi_evt_items[id - 1].words, this->_campaignId);
		break;
	}
	qDebug() << "Send cmd to pipe: " << CmdLineBuf;
	QByteArray byteCmd(CmdLineBuf);
	this->_opCmd->slotSendOperateData(byteCmd);
	//TODO need to charge command not write, maybe
}

static int getKeyValue(const char *str, const char *key, char *const value, unsigned int len)
{
	unsigned int count = 0;
	char *ptr = (char *)str;
	ptr = strstr(ptr, key);
	if (!ptr)
		goto out;

	ptr += strlen(key);
	while (ptr && *ptr && *ptr != ' ' && *ptr != ',' && *ptr != '\n' && *ptr != '\r') {
		if (count == len)
			break;
		value[count] = *ptr;
		count++;
		ptr++;
	}

out:
	if (count)
		value[count] = '\0';
	return count;
}
